#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Math;

#endregion

namespace Weazel.Gezel.Simulator.Reference
{
  [IpBlockAttribute("ram")]
  class RamBlock : AbstractIpBlock
  {
    Integer[] content;
    int wl;
    int size;

		public RamBlock(string name)
			: base(name)
    {
    }

    public override bool CannotSleepTest()
    {
      return false; // ram can always cause 'sleep' mode
    }

    public override void Run()
    {
      // perform ram function using 
      //   io vector       #
      //   -----------------------------
      //   in address      0
      //   in wr           1
      //   in rd           2
      //   in idata        3
      //   out odata       4
      if (ioValues[2].ToInt() == 1)
      {
        if (ioValues[0].ToInt() >= content.Length)
        {
          Console.WriteLine("Error: Address value for ram ip block out-of-range\n");
        }
        else
        {
          // is a read
          ioValues[4].ValueCopy(content[ioValues[0].ToInt()]);
        }
      }
      if (ioValues[1].ToInt() == 1)
      {
        if (ioValues[0].ToInt() >= content.Length)
        {
          Console.WriteLine("Error: Address value for ram ip block out-of-range\n");
        }
        else
        {
          // is a write
          content[ioValues[0].ToInt()].ValueCopy(ioValues[3]);
        }
      }
    }

    public override void SetParameter(string name)
    {
      string field = name.Substring(0, name.IndexOf('='));
      string value = name.Substring(name.IndexOf('=') + 1);

      switch (field)
      {
        case "wl":
          this.wl = int.Parse(value);
          break;
        case "size":
          this.size = int.Parse(value);
          break;
        default:
          throw new InvalidOperationException("invalid parameter '" + field + "'");
      }

      // initialize ramblock internal contents
      // when both size and wordlength has been
      // set to positive values.
      if (size > 0 && wl > 0)
      {
        List<Integer> contentsList = new List<Integer>();
        for (int i = 0; i < size; i++)
        {
          contentsList.Add(new Integer(wl, false));
        }
        this.content = contentsList.ToArray();
      }
    }

    public override bool CheckTerminal(int n, string tname, AbstractIpBlock.IoDirection dir)
    {
      switch (n)
      {
        case 0:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "address");
        case 1:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "wr");
        case 2:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "rd");
        case 3:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "idata");
        case 4:
          return (dir == AbstractIpBlock.IoDirection.Output && tname == "odata");
      }
      return false;
    }
  }
}
